package br.requisiteworks.controller;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import br.requisiteworks.modelo.Funcionario;
import br.requisiteworks.modelo.Time;
import br.requisiteworks.modelo.service.FuncionarioService;
import br.requisiteworks.modelo.service.TimeService;
import br.requisiteworks.seguranca.modelo.UsuarioLogado;
import br.requisiteworks.util.persistencia.ErroBancoDados;
import br.requisiteworks.util.persistencia.ResultadoVazio;

/**
 * Implementacao de um controller que controla as operacoes relacionadas ao
 * modulo de {@link Time}s
 * 
 * @author Leandro Chaves
 * @version 1, 30/05/2010
 */
@Controller
@Secured("ROLE_GERENTE")
@RequestMapping("/time")
public class TimeController {

	@Autowired
	private TimeService timeService;

	@Autowired
	private FuncionarioService funcionarioService;

	private static final Time VAZIO = new Time();

	@ModelAttribute
	public void preCarregaGerente(Time time) throws ResultadoVazio {
		Funcionario gerente = time.getGerente();

		if (gerente != null && gerente.getNome() == null) {
			gerente = this.funcionarioService.carregarFuncionario(gerente
					.getNumero());

			time.setGerente(gerente);
		}
	}

	@RequestMapping("/pesquisar.do")
	public List<Time> pesquisar(ModelMap model) {
		try {
			List<Time> times = this.timeService.listarTimes();
			return times;
		} catch (ResultadoVazio e) {
			model.addAttribute("erro", e.getMessage());
			return null;
		}
	}

	@RequestMapping(value = "/pesquisar.do", method = RequestMethod.POST)
	public List<Time> pesquisarTime(@RequestParam("q") String query,
			ModelMap model) {

		if (query.matches("\\d+")) {
			try {
				return Arrays.asList(this.timeService.carregarTime(Integer
						.parseInt(query)));
			} catch (ResultadoVazio e) {
				model.addAttribute("erro", e.getMessage());
				return null;
			} catch (NumberFormatException e) {
				// Nao deve ocorre devido a expressao regular
				return null;
			}
		} else {
			try {
				return this.timeService.procuraNome(query.trim());
			} catch (ResultadoVazio e) {
				model.addAttribute("erro", e.getMessage());
				return null;
			}
		}

	}

	@RequestMapping(value = "/util/pesquisar.do", method = RequestMethod.GET)
	public void pesquisar() {
	}

	@RequestMapping(value = "/util/pesquisar.do", method = RequestMethod.POST)
	public List<Time> pesquisar(@RequestParam("q") String query, ModelMap model) {

		if (query.matches("\\d+")) {
			try {
				return Arrays.asList(this.timeService.carregarTime(Integer
						.parseInt(query)));
			} catch (ResultadoVazio e) {
				model.addAttribute("erro", e.getMessage());
				return null;
			} catch (NumberFormatException e) {
				// Nao deve ocorre devido a expressao regular
				return null;
			}
		} else {
			try {
				return this.timeService.procuraNome(query.trim());
			} catch (ResultadoVazio e) {
				model.addAttribute("erro", e.getMessage());
				return null;
			}
		}

	}

	@RequestMapping(value = "/{numero}/detalhes.do", method = RequestMethod.GET)
	public String atualizar(@PathVariable("numero") Integer numero,
			ModelMap model) throws ResultadoVazio {
		Time time = this.timeService.carregarTime(numero);

		model.addAttribute("time", time);

		return "time/detalhes";
	}

	@RequestMapping(value = "/atualizar.do", method = RequestMethod.POST)
	public String atualizar(@Valid Time novoTime, BindingResult result,
			@RequestParam("nmembros") int[] membros, ModelMap model) {

		if (result.hasErrors()) {
			return null;
		}
		try {
			Time time = this.timeService.carregarTime(novoTime.getNumero());

			time.setNome(novoTime.getNome());
			time.setGerente(novoTime.getGerente());
			time.setUsuarioRegistro(UsuarioLogado.getUsername());

			List<Funcionario> funcionarios = time.getMembros();

			funcionarios.clear();

			for (int membro : membros) {
				Funcionario funcionario = this.funcionarioService
						.carregarFuncionario(membro);
				funcionarios.add(funcionario);
			}

			time.setMembros(funcionarios);

			this.timeService.atualizarTime(time);
		} catch (ErroBancoDados e) {
			model.addAttribute("erro", e.getMessage());
		}

		return "redirect:pesquisar.do";
	}

	@RequestMapping(value = "/deletar.do", method = RequestMethod.GET)
	public String deletar(@RequestParam("numero") Integer numero, ModelMap model) {
		try {
			Time time = this.timeService.carregarTime(numero);

			this.timeService.deletaTime(time);
		} catch (ErroBancoDados e) {
			model.addAttribute("erro", e.getMessage());
		}

		return "redirect:pesquisar.do";
	}

	@RequestMapping(value = "/adicionar.do", method = RequestMethod.GET)
	public Time adicionar() {
		return VAZIO;
	}

	@RequestMapping(value = "/adicionar.do", method = RequestMethod.POST)
	public String adicionar(@Valid Time time, BindingResult result,
			@RequestParam("nmembros") int[] membros, ModelMap model) {
		if (result.hasErrors()) {
			return null;
		}

		time.setUsuarioRegistro(UsuarioLogado.getUsername());

		try {
			List<Funcionario> funcionarios = new ArrayList<Funcionario>(
					membros.length);

			for (int membro : membros) {
				funcionarios.add(this.funcionarioService
						.carregarFuncionario(membro));
			}

			time.setMembros(funcionarios);

			this.timeService.salvarTime(time);
		} catch (ErroBancoDados e) {
			model.addAttribute("erro", e.getMessage());
			return null;
		}

		return "redirect:pesquisar.do";
	}
}